﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Web.Models;
using KelonProud.Administration.Domain.Organizations;
using KelonProud.Administration.Dtos;
using KelonProud.Administration.Managers.Organizations;
using KelonProud.Extensions;
using KelonProud.Mvc;
using Microsoft.EntityFrameworkCore;

namespace KelonProud.Administration.Services
{
    public interface IOrganizationAppService: IAsyncCrudAppService<OrganzationOutput,long, PagedResultRequestDto,OrganzationInput,OrganzationOutput>
    {
        Task<IEnumerable<object>> GetOrganzationTree(bool isHasNull=false,bool isHasDepartment=false);

        Task<IEnumerable<OrganzationOutput>> GetOrganzationByParentId(long? parentId);

        Task<List<object>> GetOrganizationTypes();

        Task<List<OrganzationOutput>> GetAddressLevelOrganzationByOrgId(int orgId);
    }

    [WrapResult(WrapOnSuccess = false)]
    public class OrganizationAppService: KelonProudAsyncCrudAppService<KelonProudOrganizationUnit,OrganzationOutput, long, PagedResultRequestDto, OrganzationInput, OrganzationOutput>, IOrganizationAppService
    {
        private readonly KenlonOrganizationManager _kenlonOrganizationManager;

        public OrganizationAppService(
            IRepository<KelonProudOrganizationUnit, long> repository,
            KenlonOrganizationManager kenlonOrganizationManager) : base(repository)
        {
            _kenlonOrganizationManager = kenlonOrganizationManager;
        }

        public override Task<OrganzationOutput> Save(OrganzationInput input)
        {
            if (input.Id == input.ParentId)
                throw new Exception("不能选择自己作为上级");

            var org = _kenlonOrganizationManager.GetById(input.Id) ?? new KelonProudOrganizationUnit();
            var parent = !input.ParentId.HasValue ? null : _kenlonOrganizationManager.GetById(input.ParentId.Value);

            //判断是否选择下级作为父级节点
            if (parent != null && parent.IdPath.Contains("-" + org.Id + "-"))
            {
                throw new Exception("不能选择该机构作为上级，因为该机构在当前机构的子级节点上");
            }

            if (input.OrganizationType == OrganizationType.Department &&(parent==null || parent.Level != 3))
            {
                throw new Exception("当机构类型为部门时，只能选择[街道/乡镇]作为上级");
            }

            org.Code = input.Code;
            org.DisplayName = input.DisplayName;
            org.ParentId = input.ParentId;
            org.TenantId = input.TenantId;
            org.OrganizationType = input.OrganizationType;

            org.Id = _kenlonOrganizationManager.SaveNavigation(org);

            org.IdPath = parent != null ? parent.IdPath + org.Id + "-" : "-" + org.Id + "-";
            org.NamePath = parent != null ? parent.NamePath + " > " + org.DisplayName : org.DisplayName;
            org.Level = (byte)(parent != null ?parent.Level + 1:1);

            SetChildRolePath(org);

            return Task.FromResult(org.MapTo<OrganzationOutput>());
        }

        public override Task Delete(EntityDto<long> input)
        {
            try
            {
                return base.Delete(input);
            }
            catch 
            {
                throw new Exception("该机构有关联数据，不能被删除！");
            }
        }

        public async Task<IEnumerable<object>> GetOrganzationTree(bool isHasNull = false, bool isHasDepartment = false)
        {
            var query = _kenlonOrganizationManager.Query;

            if (!isHasDepartment)
            {
                query = query.Where(w => w.OrganizationType != OrganizationType.Department);
            }

            var organs = await query.ToListAsync();
            var result = organs.Select(s => new
            {
                Id=s.Id.ToString(),
                Name=s.DisplayName,
                PId=s.ParentId,
                Open = true,
                IconSkin=s.OrganizationType== OrganizationType.Department?"department":"root",
                Type = (byte)s.OrganizationType
            }).ToList();

            if (isHasNull)
            {
                result.Insert(0, new
                {
                    Id = "",
                    Name = "无",
                    PId = (long?)-1,
                    Open = true,
                    IconSkin = "root",
                    Type = (byte)0
                });
            }

            return result;
        }

        public async Task<IEnumerable<OrganzationOutput>> GetOrganzationByParentId(long? parentId)
        {
            var query = await _kenlonOrganizationManager.Query.Where(w => w.ParentId == parentId&&w.OrganizationType== OrganizationType.General).ToListAsync();

            return query.Select(s => s.MapTo<OrganzationOutput>()).ToList();
        }

        public Task<List<object>> GetOrganizationTypes()
        {
            var nameValues = typeof(OrganizationType).GetEmunDictionary();

            var models = nameValues.Select(s => (object)new { Id = s.Value, Name = s.Key }).ToList();

            return Task.FromResult(models);
        }

        /// <summary>
        ///取得该节点所属区县下的所以街道/乡镇
        /// </summary>
        /// <param name="orgId"></param>
        /// <returns></returns>
        public Task<List<OrganzationOutput>> GetAddressLevelOrganzationByOrgId(int orgId)
        {
            var org = _kenlonOrganizationManager.GetById(orgId);

            if(org==null || org.Level!=4)
                throw  new Exception("当前组织结构不是社区/村");

            var quxianOrg = org.Parent1.Parent1;

            var result =
                _kenlonOrganizationManager.Query.Where(w => w.IdPath.Contains(quxianOrg.IdPath) && w.Level == 3).ToList()
                .Select(s=>s.MapTo<OrganzationOutput>()).ToList();

            return Task.FromResult(result) ;
        }

        private void SetChildRolePath(KelonProudOrganizationUnit organizationUnit)
        {
            organizationUnit.Children1?.Each(e =>
            {
                e.IdPath = organizationUnit.IdPath + e.Id + "-";
                e.NamePath = organizationUnit.NamePath + " > " + e.DisplayName;
                SetChildRolePath(e);
            });
        }

        /// <summary>
        /// 获取下属街道信息
        /// </summary>
        /// <param name="typeid"></param>
        /// <returns></returns>
        public IEnumerable<object> GetStreets(long orgid)
        {
            var query = _kenlonOrganizationManager.Query;
            var models = query.ToList().Where(s => s.ParentId == orgid).Select(s=>new { Id = s.Id, Name = s.DisplayName }).ToList();

            return models;
        }

    }
}
